;; NaN canonicalization tests.
;;
;; Things that are covered by spectests canonicalization
;; (`fabs`, `fneg`, `fcopysign`, `reinterpret`, `const`)
;; won't be duplicated here.

(module
  ;; Auxiliary definitions
  (type $f32-id (func (param f32) (result f32)))
  (type $f64-id (func (param f64) (result f64)))

  (table funcref
    (elem
      $nan-canonicalization-f32-func-call-target
      $nan-canonicalization-f64-func-call-target
    )
  )

  (memory 1)

  (func (export "nan-canonicalization-f32-add") (param i32) (result i32)
    (i32.reinterpret_f32 (f32.add (f32.reinterpret_i32 (get_local 0)) (f32.const 0)))
  )
  (func (export "nan-canonicalization-f32-sub") (param i32) (result i32)
    (i32.reinterpret_f32 (f32.sub (f32.reinterpret_i32 (get_local 0)) (f32.const 0)))
  )
  (func (export "nan-canonicalization-f32-mul") (param i32) (result i32)
    (i32.reinterpret_f32 (f32.mul (f32.reinterpret_i32 (get_local 0)) (f32.const 0)))
  )
  (func (export "nan-canonicalization-f32-div") (param i32) (result i32)
    (i32.reinterpret_f32 (f32.div (f32.reinterpret_i32 (get_local 0)) (f32.const 1)))
  )
  (func (export "nan-canonicalization-f32-max") (param i32) (result i32)
    (i32.reinterpret_f32 (f32.max (f32.reinterpret_i32 (get_local 0)) (f32.const 1)))
  )
  (func (export "nan-canonicalization-f32-min") (param i32) (result i32)
    (i32.reinterpret_f32 (f32.min (f32.reinterpret_i32 (get_local 0)) (f32.const 1)))
  )
  (func (export "nan-canonicalization-f32-nearest") (param i32) (result i32)
    (i32.reinterpret_f32 (f32.nearest (f32.reinterpret_i32 (get_local 0))))
  )
  (func (export "nan-canonicalization-f32-floor") (param i32) (result i32)
    (i32.reinterpret_f32 (f32.floor (f32.reinterpret_i32 (get_local 0))))
  )
  (func (export "nan-canonicalization-f32-ceil") (param i32) (result i32)
    (i32.reinterpret_f32 (f32.ceil (f32.reinterpret_i32 (get_local 0))))
  )
  (func (export "nan-canonicalization-f32-trunc") (param i32) (result i32)
    (i32.reinterpret_f32 (f32.trunc (f32.reinterpret_i32 (get_local 0))))
  )
  (func (export "nan-canonicalization-f32-sqrt") (param i32) (result i32)
    (i32.reinterpret_f32 (f32.sqrt (f32.reinterpret_i32 (get_local 0))))
  )
  (func (export "nan-canonicalization-f32-mem") (param i32) (result i32)
    (f32.store (i32.const 0) (f32.reinterpret_i32 (get_local 0)))
    (i32.reinterpret_f32 (f32.load (i32.const 0)))
  )
  (func (export "nan-canonicalization-f32-mem-cncl") (param i32) (result i32)
    (f32.store (i32.const 0) (f32.add (f32.reinterpret_i32 (get_local 0)) (f32.const 0)))
    (i32.reinterpret_f32 (f32.load (i32.const 0)))
  )
  (func (export "nan-canonicalization-f32-local") (param i32) (result i32)
    (local f32)
    (set_local 1 (f32.reinterpret_i32 (get_local 0)))
    (i32.reinterpret_f32 (get_local 1))
  )
  (func (export "nan-canonicalization-f32-local-cncl") (param i32) (result i32)
    (local f32)
    (set_local 1 (f32.add (f32.reinterpret_i32 (get_local 0)) (f32.const 0)))
    (i32.reinterpret_f32 (get_local 1))
  )
  (func $nan-canonicalization-f32-func-call-target (param f32) (result f32)
    (get_local 0)
  )
  (func (export "nan-canonicalization-f32-func-call") (param i32) (result i32)
    (i32.reinterpret_f32 (call $nan-canonicalization-f32-func-call-target (f32.reinterpret_i32 (get_local 0))))
  )
  (func (export "nan-canonicalization-f32-func-call-cncl") (param i32) (result i32)
    (i32.reinterpret_f32 (call $nan-canonicalization-f32-func-call-target (f32.add (f32.reinterpret_i32 (get_local 0)) (f32.const 0))))
  )
  (func (export "nan-canonicalization-f32-func-call-indirect") (param i32) (result i32)
    (i32.reinterpret_f32 (call_indirect (type $f32-id) (f32.reinterpret_i32 (get_local 0)) (i32.const 0)))
  )
  (func (export "nan-canonicalization-f32-func-call-indirect-cncl") (param i32) (result i32)
    (i32.reinterpret_f32 (call_indirect (type $f32-id) (f32.add (f32.reinterpret_i32 (get_local 0)) (f32.const 0)) (i32.const 0)))
  )

  (func (export "nan-canonicalization-f64-add") (param i64) (result i64)
    (i64.reinterpret_f64 (f64.add (f64.reinterpret_i64 (get_local 0)) (f64.const 0)))
  )
  (func (export "nan-canonicalization-f64-sub") (param i64) (result i64)
    (i64.reinterpret_f64 (f64.sub (f64.reinterpret_i64 (get_local 0)) (f64.const 0)))
  )
  (func (export "nan-canonicalization-f64-mul") (param i64) (result i64)
    (i64.reinterpret_f64 (f64.mul (f64.reinterpret_i64 (get_local 0)) (f64.const 0)))
  )
  (func (export "nan-canonicalization-f64-div") (param i64) (result i64)
    (i64.reinterpret_f64 (f64.div (f64.reinterpret_i64 (get_local 0)) (f64.const 1)))
  )
  (func (export "nan-canonicalization-f64-max") (param i64) (result i64)
    (i64.reinterpret_f64 (f64.max (f64.reinterpret_i64 (get_local 0)) (f64.const 1)))
  )
  (func (export "nan-canonicalization-f64-min") (param i64) (result i64)
    (i64.reinterpret_f64 (f64.min (f64.reinterpret_i64 (get_local 0)) (f64.const 1)))
  )
  (func (export "nan-canonicalization-f64-nearest") (param i64) (result i64)
    (i64.reinterpret_f64 (f64.nearest (f64.reinterpret_i64 (get_local 0))))
  )
  (func (export "nan-canonicalization-f64-floor") (param i64) (result i64)
    (i64.reinterpret_f64 (f64.floor (f64.reinterpret_i64 (get_local 0))))
  )
  (func (export "nan-canonicalization-f64-ceil") (param i64) (result i64)
    (i64.reinterpret_f64 (f64.ceil (f64.reinterpret_i64 (get_local 0))))
  )
  (func (export "nan-canonicalization-f64-trunc") (param i64) (result i64)
    (i64.reinterpret_f64 (f64.trunc (f64.reinterpret_i64 (get_local 0))))
  )
  (func (export "nan-canonicalization-f64-sqrt") (param i64) (result i64)
    (i64.reinterpret_f64 (f64.sqrt (f64.reinterpret_i64 (get_local 0))))
  )
  (func (export "nan-canonicalization-f64-mem") (param i64) (result i64)
    (f64.store (i32.const 0) (f64.reinterpret_i64 (get_local 0)))
    (i64.reinterpret_f64 (f64.load (i32.const 0)))
  )
  (func (export "nan-canonicalization-f64-mem-cncl") (param i64) (result i64)
    (f64.store (i32.const 0) (f64.add (f64.reinterpret_i64 (get_local 0)) (f64.const 0)))
    (i64.reinterpret_f64 (f64.load (i32.const 0)))
  )
  (func (export "nan-canonicalization-f64-local") (param i64) (result i64)
    (local f64)
    (set_local 1 (f64.reinterpret_i64 (get_local 0)))
    (i64.reinterpret_f64 (get_local 1))
  )
  (func (export "nan-canonicalization-f64-local-cncl") (param i64) (result i64)
    (local f64)
    (set_local 1 (f64.add (f64.reinterpret_i64 (get_local 0)) (f64.const 0)))
    (i64.reinterpret_f64 (get_local 1))
  )
  (func $nan-canonicalization-f64-func-call-target (param f64) (result f64)
    (get_local 0)
  )
  (func (export "nan-canonicalization-f64-func-call") (param i64) (result i64)
    (i64.reinterpret_f64 (call $nan-canonicalization-f64-func-call-target (f64.reinterpret_i64 (get_local 0))))
  )
  (func (export "nan-canonicalization-f64-func-call-cncl") (param i64) (result i64)
    (i64.reinterpret_f64 (call $nan-canonicalization-f64-func-call-target (f64.add (f64.reinterpret_i64 (get_local 0)) (f64.const 0))))
  )
  (func (export "nan-canonicalization-f64-func-call-indirect") (param i64) (result i64)
    (i64.reinterpret_f64 (call_indirect (type $f64-id) (f64.reinterpret_i64 (get_local 0)) (i32.const 1)))
  )
  (func (export "nan-canonicalization-f64-func-call-indirect-cncl") (param i64) (result i64)
    (i64.reinterpret_f64 (call_indirect (type $f64-id) (f64.add (f64.reinterpret_i64 (get_local 0)) (f64.const 0)) (i32.const 1)))
  )
)

(assert_return (invoke "nan-canonicalization-f32-add" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-sub" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-mul" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-div" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-max" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-min" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-nearest" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-floor" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-ceil" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-trunc" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-sqrt" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-mem" (i32.const 0x7fc00001)) (i32.const 0x7fc00001))
(assert_return (invoke "nan-canonicalization-f32-mem-cncl" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-local" (i32.const 0x7fc00001)) (i32.const 0x7fc00001))
(assert_return (invoke "nan-canonicalization-f32-local-cncl" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-func-call" (i32.const 0x7fc00001)) (i32.const 0x7fc00001))
(assert_return (invoke "nan-canonicalization-f32-func-call-cncl" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))
(assert_return (invoke "nan-canonicalization-f32-func-call-indirect" (i32.const 0x7fc00001)) (i32.const 0x7fc00001))
(assert_return (invoke "nan-canonicalization-f32-func-call-indirect-cncl" (i32.const 0x7fc00001)) (i32.const 0x7fc00000))

(assert_return (invoke "nan-canonicalization-f64-add" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-sub" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-mul" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-div" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-max" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-min" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-nearest" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-floor" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-ceil" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-trunc" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-sqrt" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-mem" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000001))
(assert_return (invoke "nan-canonicalization-f64-mem-cncl" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-local" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000001))
(assert_return (invoke "nan-canonicalization-f64-local-cncl" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-func-call" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000001))
(assert_return (invoke "nan-canonicalization-f64-func-call-cncl" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))
(assert_return (invoke "nan-canonicalization-f64-func-call-indirect" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000001))
(assert_return (invoke "nan-canonicalization-f64-func-call-indirect-cncl" (i64.const 0x7ff8000000000001)) (i64.const 0x7ff8000000000000))

;; Test canonicalization is done before branch in `else` operator.
(module
  (func (;0;)
    (local f64)
    i32.const 1
    if (result f64)
      local.get 0
      f64.const 0x1p+0 (;=1;)
      f64.add
    else
      f64.const 0x0p+0 (;=0;)
    end
    return
  )
)

;; Test canonicalization is done before branch in `return` operator.
(module
  (func (;0;) (result f64)
    (local f64)
    f64.const 0x0p+0
    local.get 0
    f64.mul
    return
  )
)
